package cn.iocoder.yudao.module.hs.service.picktask;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.hs.controller.admin.material.vo.MaterialRespVO;
import cn.iocoder.yudao.module.hs.controller.admin.picktask.vo.PickTaskPageReqVO;
import cn.iocoder.yudao.module.hs.controller.admin.picktask.vo.PickTaskSaveReqVO;
import cn.iocoder.yudao.module.hs.controller.admin.picktaskmaterial.vo.StartPickMaterialVO;
import cn.iocoder.yudao.module.hs.controller.admin.picktaskmaterial.vo.StartPickVO;
import cn.iocoder.yudao.module.hs.controller.admin.shiporder.vo.ShipOrderSaveReqVO;
import cn.iocoder.yudao.module.hs.dal.dataobject.material.MaterialDO;
import cn.iocoder.yudao.module.hs.dal.dataobject.picktask.PickTaskDO;
import cn.iocoder.yudao.module.hs.dal.dataobject.picktaskmaterial.PickTaskMaterialDO;
import cn.iocoder.yudao.module.hs.dal.dataobject.rfid.RfidDO;
import cn.iocoder.yudao.module.hs.dal.dataobject.shiporder.ShipOrderDO;
import cn.iocoder.yudao.module.hs.dal.dataobject.shiporderdetail.ShipOrderDetailDO;
import cn.iocoder.yudao.module.hs.dal.dataobject.warehouse.WarehouseDO;
import cn.iocoder.yudao.module.hs.dal.mysql.picktask.PickTaskMapper;
import cn.iocoder.yudao.module.hs.dal.mysql.picktaskmaterial.PickTaskMaterialMapper;
import cn.iocoder.yudao.module.hs.dal.redis.RedisKeyConstants;
import cn.iocoder.yudao.module.hs.dal.redis.no.OrderNoRedisDAO;
import cn.iocoder.yudao.module.hs.enums.material.MaterialOperateTypeEnum;
import cn.iocoder.yudao.module.hs.enums.materialmode.MaterialModeConstants;
import cn.iocoder.yudao.module.hs.enums.picktask.PickTaskStatusEnum;
import cn.iocoder.yudao.module.hs.enums.picktask.PickTaskTypeEnum;
import cn.iocoder.yudao.module.hs.enums.shiporder.ShipOrderStatusEnum;
import cn.iocoder.yudao.module.hs.enums.warehouse.WarehouseTypeEnum;
import cn.iocoder.yudao.module.hs.framework.core.annotations.MaterialLog;
import cn.iocoder.yudao.module.hs.framework.core.utils.MaterialLogUtils;
import cn.iocoder.yudao.module.hs.netty.RFIDLight;
import cn.iocoder.yudao.module.hs.service.material.MaterialService;
import cn.iocoder.yudao.module.hs.service.picktaskmaterial.PickTaskMaterialService;
import cn.iocoder.yudao.module.hs.service.picktaskmaterialdetail.PickTaskMaterialDetailService;
import cn.iocoder.yudao.module.hs.service.rfid.RfidService;
import cn.iocoder.yudao.module.hs.service.shiporder.ShipOrderService;
import cn.iocoder.yudao.module.hs.service.shiporderdetail.ShipOrderDetailService;
import cn.iocoder.yudao.module.hs.service.warehouse.WarehouseService;
import cn.iocoder.yudao.module.hs.util.RedisUtil;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.hs.enums.ErrorCodeConstants.*;

/**
 * 拣货任务 Service 实现类
 *
 * @author 航盛
 */
@Service
@Validated
@Slf4j
public class PickTaskServiceImpl implements PickTaskService {

    @Resource
    private PickTaskMapper pickTaskMapper;
    @Resource
    private OrderNoRedisDAO orderNoRedisDAO;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private WarehouseService warehouseService;
    @Resource
    private ShipOrderService shipOrderService;
    @Resource
    private ShipOrderDetailService shipOrderDetailService;
    @Resource
    private PickTaskMaterialService pickTaskMaterialService;
    @Resource
    private PickTaskMaterialDetailService pickTaskMaterialDetailService;
    @Resource
    private MaterialService materialService;
    @Resource
    private RfidService rfidService;
    @Resource
    private PickTaskMaterialMapper pickTaskMaterialMapper;

    @Override
    @Transactional
    public Long createPickTask(PickTaskSaveReqVO createReqVO) {
        if (PickTaskTypeEnum.CHANGE_RFID.getType().equals(createReqVO.getTaskType())) {
            return createRfidLowBatteryTask(createReqVO);
        }
        ShipOrderDO shipOrder = shipOrderService.getShipOrder(createReqVO.getShipOrderCode());
        if (shipOrder == null) {
            throw exception(SHIP_ORDER_NOT_EXISTS);
        }
        List<ShipOrderDetailDO> shipOrderDetailList = shipOrderDetailService.getShipOrderDetailList(shipOrder.getId());
        if (CollUtil.isEmpty(shipOrderDetailList)) {
            throw exception(SHIP_ORDER_DETAIL_NOT_EXISTS);
        }
        PickTaskDO existsPickTask = getPickTask(createReqVO.getShipOrderCode());
        if (existsPickTask != null) {
            throw exception(PICK_TASK_EXISTS);
        }
        for (ShipOrderDetailDO shipOrderDetailDO : shipOrderDetailList) {
            List<MaterialDO> materials = materialService.getMaterials(shipOrder.getWarehouseId(), shipOrderDetailDO.getModeCode());
            if (materials.size() < shipOrderDetailDO.getMaterialCount()) {
                throw exception(SHIP_ORDER_DETAIL_MATERIAL_NOT_ENOUGH);
            }
        }
        WarehouseDO warehouse = warehouseService.getWarehouse(shipOrder.getWarehouseId());
        if (warehouse == null) {
            throw exception(WAREHOUSE_NOT_EXISTS);
        }
        List<String> statusList = new ArrayList<>();
        statusList.add(PickTaskStatusEnum.TO_BE_PICKED.getStatus());
        statusList.add(PickTaskStatusEnum.PICKING.getStatus());
        Long pickTaskCount = getPickTaskCount(warehouse.getId(), statusList);
        if (pickTaskCount > 0) {
            throw exception(PICK_TASK_COUNT_LIMIT);
        }
        // 插入
        PickTaskDO pickTask = BeanUtils.toBean(createReqVO, PickTaskDO.class);
        pickTask.setShipOrderId(shipOrder.getId());
        pickTask.setCode(orderNoRedisDAO.generate(OrderNoRedisDAO.PICK_TASK_NO_PREFIX, RedisKeyConstants.PICK_TASK_NO));
        pickTask.setTaskType(PickTaskTypeEnum.PICK.getType());
        pickTask.setStatus(PickTaskStatusEnum.TO_BE_PICKED.getStatus());
        pickTask.setWarehouseType(warehouse.getWarehouseType());
        // 如果AssignUserId不为0 且不为空，则给指定人分配任务，其他情况都分配给所有人
        if (pickTask.getAssignUserId() != null && !pickTask.getAssignUserId().equals(0L)) {
            AdminUserRespDTO assignUser = adminUserApi.getUser(pickTask.getAssignUserId());
            if (assignUser != null) {
                pickTask.setAssignUserName(assignUser.getNickname());
            } else {
                // 分配给所有人
                pickTask.setAssignUserId(null);
                pickTask.setAssignUserName("所有人");
            }
        } else {
            // 分配给所有人
            pickTask.setAssignUserId(null);
        }
        pickTask.setWarehouseId(warehouse.getId());
        pickTask.setDeptId(warehouse.getDeptId());
        pickTaskMapper.insert(pickTask);

        // 合并物料代码相同的记录，创建拣货记录
        List<ShipOrderDetailDO> collectList = shipOrderDetailList.stream()
                .collect(Collectors.groupingBy(ShipOrderDetailDO::getModeCode,
                        LinkedHashMap::new, // 保证顺序
                        Collectors.reducing(
                                (a, b) -> new ShipOrderDetailDO(
                                        a.getId(), // 可根据需要调整 id 处理方式
                                        a.getShipOrderId(),
                                        a.getMaterialName(), // 保留第一个的 materialName
                                        a.getModeCode(),
                                        a.getMaterialCount() + b.getMaterialCount() // 累加 materialCount
                                )
                        )
                ))
                .values().stream()
                .filter(Optional::isPresent)
                .map(Optional::get)
                .collect(Collectors.toList());
        // 插入拣货任务物料机型明细
        List<PickTaskMaterialDO> pickTaskMaterialList = new ArrayList<>();
        for (ShipOrderDetailDO shipOrderDetailDO : collectList) {
            PickTaskMaterialDO pickTaskMaterialDO = new PickTaskMaterialDO();
            pickTaskMaterialDO.setPickTaskId(pickTask.getId());
            pickTaskMaterialDO.setShipOrderId(shipOrder.getId());
            pickTaskMaterialDO.setMaterialModeCode(shipOrderDetailDO.getModeCode());
            pickTaskMaterialDO.setMaterialName(shipOrderDetailDO.getMaterialName());
            pickTaskMaterialDO.setMaterialCount(shipOrderDetailDO.getMaterialCount());
            pickTaskMaterialDO.setStatus(PickTaskStatusEnum.TO_BE_PICKED.getStatus());
            pickTaskMaterialList.add(pickTaskMaterialDO);
        }
        pickTaskMaterialService.insertBatch(pickTaskMaterialList);

        // 更新出库单状态为待拣货
        shipOrder.setStatus(ShipOrderStatusEnum.TO_BE_PICKED.getStatus());
        shipOrderService.updateShipOrder(BeanUtils.toBean(shipOrder, ShipOrderSaveReqVO.class));

        // 返回
        return pickTask.getId();
    }

    @Override
    public void updatePickTask(PickTaskSaveReqVO updateReqVO) {
        // 校验存在
        validatePickTaskExists(updateReqVO.getId());
        // 更新
        PickTaskDO updateObj = BeanUtils.toBean(updateReqVO, PickTaskDO.class);
        pickTaskMapper.updateById(updateObj);
    }

    @Override
    public void deletePickTask(Long shipOrderId) {
        // 删除
        pickTaskMapper.delete(PickTaskDO::getShipOrderId, shipOrderId);
    }

    private void validatePickTaskExists(Long id) {
        if (pickTaskMapper.selectById(id) == null) {
            throw exception(PICK_TASK_NOT_EXISTS);
        }
    }

    @Override
    public PickTaskDO getPickTask(Long id) {
        return pickTaskMapper.selectById(id);
    }

    @Override
    public PageResult<PickTaskDO> getPickTaskPage(PickTaskPageReqVO pageReqVO) {
        return pickTaskMapper.selectPage(pageReqVO);
    }

    @Override
    public PickTaskDO getPickTask(String shipOrderCode) {
        return pickTaskMapper.selectOne(PickTaskDO::getShipOrderCode, shipOrderCode);
    }

    @Override
    public StartPickVO getStartPick(Long pickTaskId) {
        PickTaskDO pickTask = pickTaskMapper.selectById(pickTaskId);
        if (pickTask == null) {
            throw exception(PICK_TASK_NOT_EXISTS);
        }
        if (PickTaskStatusEnum.PICK_OVER.getStatus().equals(pickTask.getStatus())) {
            throw exception(PICK_TASK_STATUS_ERROR);
        }
        ShipOrderDO shipOrder = shipOrderService.getShipOrder(pickTask.getShipOrderId());
        if (shipOrder == null) {
            throw exception(SHIP_ORDER_NOT_EXISTS);
        }
        List<PickTaskMaterialDO> pickTaskMaterialList = pickTaskMaterialService.getPickTaskMaterialList(pickTaskId);
        if (CollUtil.isEmpty(pickTaskMaterialList)) {
            throw exception(PICK_TASK_MATERIAL_NOT_EXISTS);
        }
        // redis锁
        RedisUtil.getPickTaskLock(pickTask.getCode(), getLoginUserId());

        StartPickVO startPickVO = new StartPickVO();
        startPickVO.setPickTaskId(pickTaskId);
        startPickVO.setPickTaskCode(pickTask.getCode());
        startPickVO.setStatus(PickTaskStatusEnum.PICKING.getStatus());
        int totalMaterialCount = pickTaskMaterialList.stream()
                .mapToInt(PickTaskMaterialDO::getMaterialCount)
                .sum();
        startPickVO.setCount(totalMaterialCount);

        WarehouseDO warehouse = warehouseService.getWarehouse(pickTask.getWarehouseId());
        if (warehouse == null) {
            throw exception(WAREHOUSE_NOT_EXISTS);
        }
        // 先进先出的仓库，需要计算待拣取物料范围
        if (warehouse.getFirstInOut()) {
            List<StartPickMaterialVO> toBePickedMaterialList = getToBePickedMaterialList(pickTask.getCode(), pickTaskMaterialList, pickTask.getWarehouseId());
            List<MaterialDO> selectedMaterials = RedisUtil.getSelectedMaterials(pickTask.getCode());
            startPickVO.setPickCountTotal(CollUtil.isEmpty(selectedMaterials) ? 0 : selectedMaterials.size());
            startPickVO.setList(toBePickedMaterialList);
        }
        // 待拣范围存储到redis中
        RedisUtil.startPick(pickTask.getCode(), startPickVO);
        if (PickTaskStatusEnum.TO_BE_PICKED.getStatus().equals(pickTask.getStatus())) {
            startPickVO.setStatus(PickTaskStatusEnum.PICKING.getStatus());
            pickTask.setStatus(PickTaskStatusEnum.PICKING.getStatus());
            pickTask.setPickStartTime(LocalDateTime.now());
            pickTaskMapper.updateById(pickTask);
        }
        if (ShipOrderStatusEnum.TO_BE_PICKED.getStatus().equals(shipOrder.getStatus())) {
            shipOrder.setStatus(ShipOrderStatusEnum.PICKING.getStatus());
            shipOrderService.updateShipOrder(BeanUtils.toBean(shipOrder, ShipOrderSaveReqVO.class));
        }
        return startPickVO;
    }

    @Override
    @Transactional
    public void complete(Long pickTaskId) {
        PickTaskDO pickTask = this.getPickTask(pickTaskId);
        pickTask.setStatus(PickTaskStatusEnum.PICK_OVER.getStatus());
        pickTask.setPickCompleteTime(LocalDateTime.now());
        this.updatePickTask(BeanUtils.toBean(pickTask, PickTaskSaveReqVO.class));

        // 更新发货单状态为已完成
        ShipOrderDO shipOrder = shipOrderService.getShipOrder(pickTask.getShipOrderId());
        // 查询仓库是否有出库区
        WarehouseDO warehouse = warehouseService.getWarehouse(pickTask.getWarehouseId());
        if (warehouse.getHaveWaitingArea()) {
            shipOrder.setStatus(ShipOrderStatusEnum.PICK_OVER.getStatus());
        } else {
            List<MaterialDO> selectedMaterials = RedisUtil.getSelectedMaterials(pickTask.getCode());
            if (warehouse.getWarehouseType().equals(WarehouseTypeEnum.PRODUCTION.getType())) {
                shipOrderService.materialLogProductionShip(selectedMaterials.stream().map(MaterialDO::getId).collect(Collectors.toList()));
            }
            if (warehouse.getWarehouseType().equals(WarehouseTypeEnum.TRIPARTITE.getType())) {
                shipOrderService.materialLogTripartiteShip(selectedMaterials.stream().map(MaterialDO::getId).collect(Collectors.toList()));
            }
            shipOrder.setStatus(ShipOrderStatusEnum.OUTING.getStatus());
            shipOrder.setOutingTime(LocalDateTime.now());
        }
        shipOrderService.updateShipOrder(BeanUtils.toBean(shipOrder, ShipOrderSaveReqVO.class));

        Long toWarehouseDeptId = null;
        if (warehouse.getWarehouseType().equals(WarehouseTypeEnum.TRIPARTITE.getType())) {
            WarehouseDO toWarehouse = warehouseService.getWarehouse(shipOrder.getWarehouseId());
            toWarehouseDeptId = toWarehouse.getDeptId();
        } else {
            if (MaterialModeConstants.IS_DIRECT_NO.equals(shipOrder.getIsDirect())) {
                WarehouseDO toWarehouse = warehouseService.getWarehouse(shipOrder.getToWarehouseId());
                toWarehouseDeptId = toWarehouse.getDeptId();
            }
        }

        // 插入拣货明细
        pickTaskMaterialDetailService.insertPickTaskMaterialDetail(pickTask, toWarehouseDeptId);

        // 释放任务锁
        RedisUtil.releasePickTaskLock(pickTask.getCode());
        // 清空拣货任务缓存
        RedisUtil.removeStartPick(pickTask.getCode());
        // 清空已拣物料缓存
        RedisUtil.removeSelectedMaterials(pickTask.getCode());
        // 任务完成后，释放拣货中的物料
        RedisUtil.removePickingMaterials(pickTask.getCode());
    }

    @Override
    public void clearPickingData(String modeCode) {
        RedisUtil.removePickingMaterialsByModeCode(modeCode);
    }

    @Override
    public List<PickTaskDO> getLowBatteryPickTask(String rfidCode) {
        LambdaQueryWrapperX<PickTaskDO> query = new LambdaQueryWrapperX<>();
        query.eq(PickTaskDO::getRfidCode, rfidCode)
                .eq(PickTaskDO::getTaskType, PickTaskTypeEnum.CHANGE_RFID.getType())
                .eq(PickTaskDO::getStatus, PickTaskStatusEnum.TO_BE_PICKED.getStatus());
        return pickTaskMapper.selectList(query);

    }

    /**
     * 确定物料拣取范围，并按照入库时间和大数规则进行排序
     *
     * @param pickTaskMaterialList 拣货机型清单
     * @return 物料拣取范围
     */
    private List<StartPickMaterialVO> getToBePickedMaterialList(String pickTaskCode, List<PickTaskMaterialDO> pickTaskMaterialList, Long warehouseId) {
        List<StartPickMaterialVO> startPickMaterialList = new ArrayList<>();
        List<MaterialDO> selectedMaterials = RedisUtil.getSelectedMaterials(pickTaskCode);
        for (PickTaskMaterialDO pickTaskMaterial : pickTaskMaterialList) {
            List<MaterialRespVO> materialsOnTray = BeanUtils.toBean(materialService.getMaterials(warehouseId, pickTaskMaterial.getMaterialModeCode()), MaterialRespVO.class);
            List<MaterialRespVO> materials = new ArrayList<>(materialsOnTray);
            List<MaterialRespVO> pickingMaterials = RedisUtil.getPickingMaterialsKey();
            if (CollUtil.isNotEmpty(pickingMaterials)) {
                for (MaterialRespVO pickingMaterial : pickingMaterials) {
                    // 如果被选中的物料和当前物料不是同一个拣货任务，则从待拣物料中移除
                    materials.removeIf(material -> !pickingMaterial.getPickTaskCode().equals(pickTaskCode) &&
                            material.getCode().equals(pickingMaterial.getCode()));
                }
            }
            if (CollUtil.isEmpty(materials) || materials.size() < pickTaskMaterial.getMaterialCount()) {
                throw exception(PICK_TASK_MATERIAL_NOT_ENOUGH);
            }
            List<MaterialRespVO> toBePickedMaterials = materials.subList(0, pickTaskMaterial.getMaterialCount());
            if (CollUtil.isNotEmpty(pickingMaterials)) {
                List<MaterialRespVO> collect = pickingMaterials.stream().filter(materialRespVO -> materialRespVO.getPickTaskCode().equals(pickTaskCode)).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(collect)) {
                    toBePickedMaterials = materialsOnTray.stream()
                            .filter(material -> collect.stream()
                                    .anyMatch(collectMaterial -> collectMaterial.getCode().equals(material.getCode())))
                            .collect(Collectors.toList());
                }
            }
            List<MaterialRespVO> leftMaterialRespVOS = new ArrayList<>(materialsOnTray);
            leftMaterialRespVOS.removeAll(toBePickedMaterials);
            Set<String> boxCodeSet = CollectionUtils.convertSet(toBePickedMaterials, MaterialRespVO::getBoxCode);
            Set<String> leftBoxSet = CollectionUtils.convertSet(leftMaterialRespVOS, MaterialRespVO::getBoxCode);
            Set<String> redBoxSet = new HashSet<>();
            for (String boxCode : boxCodeSet) {
                if (leftBoxSet.contains(boxCode)) {
                    redBoxSet.add(boxCode);
                }
            }
            Set<String> trayCodeSet = CollectionUtils.convertSet(toBePickedMaterials, MaterialRespVO::getTrayCode);
            Set<String> leftTraySet = CollectionUtils.convertSet(leftMaterialRespVOS, MaterialRespVO::getTrayCode);
            Set<String> yellowTraySet = new HashSet<>();
            for (String trayCode : trayCodeSet) {
                if (leftTraySet.contains(trayCode)) {
                    yellowTraySet.add(trayCode);
                }
            }
            // 按托盘分组
            Map<String, RfidDO> trayRfidMap = rfidService.getRfidByTrayCode(trayCodeSet);
            Map<String, List<MaterialRespVO>> groupedByTrayCode = toBePickedMaterials.stream()
                    .collect(Collectors.groupingBy(MaterialRespVO::getTrayCode));
            for (String trayCode : groupedByTrayCode.keySet()) {
                RfidDO rfid = trayRfidMap.get(trayCode);
                if (rfid == null) {
                    throw exception(PICK_TASK_RFID_NOT_FOUND, trayCode);
                }
                StartPickMaterialVO startPickMaterialVO = new StartPickMaterialVO();
                startPickMaterialVO.setPickTaskId(pickTaskMaterial.getPickTaskId());
                startPickMaterialVO.setRfidCode(rfid.getCode());
                startPickMaterialVO.setTrayCode(trayCode);
                startPickMaterialVO.setMaterialModeCode(pickTaskMaterial.getMaterialModeCode());
                startPickMaterialVO.setWarehousingTime(rfid.getWarehousingTime());
                startPickMaterialVO.setCount(groupedByTrayCode.get(trayCode).size());
                for (MaterialRespVO toBePickedMaterial : groupedByTrayCode.get(trayCode)) {
                    if (redBoxSet.contains(toBePickedMaterial.getBoxCode())) {
                        startPickMaterialVO.setLightName(RFIDLight.RED.getName());
                        startPickMaterialVO.setLight(RFIDLight.RED.getLight());
                        startPickMaterialVO.setLightSort(3);
                        continue;
                    }
                    if (yellowTraySet.contains(toBePickedMaterial.getTrayCode())) {
                        startPickMaterialVO.setLightName(RFIDLight.YELLOW.getName());
                        startPickMaterialVO.setLight(RFIDLight.YELLOW.getLight());
                        startPickMaterialVO.setLightSort(2);
                        continue;
                    }
                    startPickMaterialVO.setLightName(RFIDLight.GREEN.getName());
                    startPickMaterialVO.setLight(RFIDLight.GREEN.getLight());
                    startPickMaterialVO.setLightSort(1);
                }
                startPickMaterialVO.setMaterialRespVOList(groupedByTrayCode.get(trayCode));
                if (startPickMaterialVO.getLight().equals(RFIDLight.GREEN.getLight())) {
                    List<MaterialRespVO> materialListByTrayCode = groupedByTrayCode.get(trayCode);
                    if (materialListByTrayCode.size() > startPickMaterialVO.getMaterialRespVOList().size()) {
                        for (MaterialRespVO materialRespVO : startPickMaterialVO.getMaterialRespVOList()) {
                            if (StrUtil.isEmpty(materialRespVO.getBoxCode())) {
                                startPickMaterialVO.setLightName(RFIDLight.RED.getName());
                                startPickMaterialVO.setLight(RFIDLight.RED.getLight());
                                startPickMaterialVO.setLightSort(3);
                            }
                        }
                    }
                }
                if (RFIDLight.RED.getLight().equals(startPickMaterialVO.getLight())) {
                    List<StartPickMaterialVO> startPickMaterialVOS = divideRedLightTray(leftMaterialRespVOS, startPickMaterialVO);
                    if (CollUtil.isNotEmpty(startPickMaterialVOS)) {
                        for (StartPickMaterialVO pickMaterialVO : startPickMaterialVOS) {
                            getPickCount(selectedMaterials, pickMaterialVO);
                        }
                        startPickMaterialList.addAll(startPickMaterialVOS);
                    }
                    // 如果为黄灯的时候，要判断一下是否为无箱码的单独物料
                } else if (RFIDLight.YELLOW.getLight().equals(startPickMaterialVO.getLight())) {
                    List<MaterialRespVO> materialRespVOList = startPickMaterialVO.getMaterialRespVOList();
                    boolean noBoxFlg = true;
                    for (MaterialRespVO materialRespVO : materialRespVOList) {
                        if (StrUtil.isNotEmpty(materialRespVO.getBoxCode())) {
                            noBoxFlg = false;
                            break;
                        }
                    }
                    if (noBoxFlg) {
                        startPickMaterialVO.setLightName(RFIDLight.RED.getName());
                        startPickMaterialVO.setLight(RFIDLight.RED.getLight());
                        startPickMaterialVO.setLightSort(3);
                    }
                    startPickMaterialList.add(startPickMaterialVO);
                    getPickCount(selectedMaterials, startPickMaterialVO);
                } else {
                    startPickMaterialList.add(startPickMaterialVO);
                    getPickCount(selectedMaterials, startPickMaterialVO);
                }
            }
            if (PickTaskStatusEnum.TO_BE_PICKED.getStatus().equals(pickTaskMaterial.getStatus())) {
                pickTaskMaterial.setStatus(PickTaskStatusEnum.PICKING.getStatus());
                pickTaskMaterialMapper.updateById(pickTaskMaterial);
            }
        }
        List<MaterialRespVO> allMaterials = new ArrayList<>();
        for (StartPickMaterialVO startPickMaterialVO : startPickMaterialList) {
            for (MaterialRespVO materialRespVO : startPickMaterialVO.getMaterialRespVOList()) {
                materialRespVO.setPickTaskCode(pickTaskCode);
                allMaterials.add(materialRespVO);
            }
        }
        // 将待拣货物全部标记为拣货中
        RedisUtil.addPickingMaterials(allMaterials);

        // 按照lightSort升序排序，再按照warehousingTime升序排序
        startPickMaterialList.sort(Comparator.comparingInt(StartPickMaterialVO::getLightSort).thenComparing(StartPickMaterialVO::getWarehousingTime));
        return startPickMaterialList;
    }

    private void getPickCount(List<MaterialDO> selectedMaterials, StartPickMaterialVO startPickMaterialVO) {
        int pickCount = 0;
        if (CollUtil.isNotEmpty(selectedMaterials)) {
            for (MaterialDO selectedMaterial : selectedMaterials) {
                for (MaterialRespVO materialRespVO : startPickMaterialVO.getMaterialRespVOList()) {
                    if (selectedMaterial.getCode().equals(materialRespVO.getCode())) {
                        pickCount++;
                    }
                }
            }
        }
        startPickMaterialVO.setPickCount(pickCount);
    }

    /**
     * 如果当前子任务为红灯托盘，则进一步判断是否包含整箱拾取，如果包含则将所有整箱的物料单独拆分一个子任务，其余红色拆箱的分配到一个子任务
     *
     * @param leftMaterialRespVOS
     * @param startPickMaterialVO
     * @return
     */
    private List<StartPickMaterialVO> divideRedLightTray(List<MaterialRespVO> leftMaterialRespVOS, StartPickMaterialVO startPickMaterialVO) {
        Set<String> boxCodeSet = CollectionUtils.convertSet(startPickMaterialVO.getMaterialRespVOList(), MaterialRespVO::getBoxCode);
        Set<String> leftBoxCodeSet = CollectionUtils.convertSet(leftMaterialRespVOS, MaterialRespVO::getBoxCode);
        Set<String> redBoxSet = new HashSet<>();
        Set<String> yellowBoxSet = new HashSet<>();
        for (String boxCode : boxCodeSet) {
            if (leftBoxCodeSet.contains(boxCode)) {
                redBoxSet.add(boxCode);
            } else {
                yellowBoxSet.add(boxCode);
            }
        }
        List<StartPickMaterialVO> startPickMaterialList = new ArrayList<>();
        // 如果没有红灯灯的箱子，则说明异常情况，终止
        if (redBoxSet.isEmpty()) {
            log.error("红灯托盘拆分逻辑异常，任务ID {}，RFID编号 {}", startPickMaterialVO.getPickTaskId(), startPickMaterialVO.getRfidCode());
            return null;
        }
        // 如果没有黄灯的箱子，则说明当前托盘上只有拆箱逻辑红灯，无需继续拆分
        if (yellowBoxSet.isEmpty()) {
            log.info("只有拆箱逻辑红灯，无需继续拆分");
            startPickMaterialList.add(startPickMaterialVO);
            return startPickMaterialList;
        }
        List<MaterialRespVO> redCollect = startPickMaterialVO.getMaterialRespVOList().stream().filter(materialRespVO -> redBoxSet.contains(materialRespVO.getBoxCode())).collect(Collectors.toList());
        StartPickMaterialVO redStartPickMaterialVO = new StartPickMaterialVO();
        BeanUtils.copyProperties(startPickMaterialVO, redStartPickMaterialVO);
        redStartPickMaterialVO.setMaterialRespVOList(redCollect);
        redStartPickMaterialVO.setCount(redCollect.size());
        redStartPickMaterialVO.setLight(RFIDLight.RED.getLight());
        redStartPickMaterialVO.setLightName(RFIDLight.RED.getName());
        redStartPickMaterialVO.setLightSort(3);
        startPickMaterialList.add(redStartPickMaterialVO);

        List<MaterialRespVO> yellowCollect = startPickMaterialVO.getMaterialRespVOList().stream().filter(materialRespVO -> yellowBoxSet.contains(materialRespVO.getBoxCode())).collect(Collectors.toList());
        StartPickMaterialVO yellowStartPickMaterialVO = new StartPickMaterialVO();
        BeanUtils.copyProperties(startPickMaterialVO, yellowStartPickMaterialVO);
        yellowStartPickMaterialVO.setMaterialRespVOList(yellowCollect);
        yellowStartPickMaterialVO.setCount(yellowCollect.size());
        yellowStartPickMaterialVO.setLight(RFIDLight.YELLOW.getLight());
        yellowStartPickMaterialVO.setLightName(RFIDLight.YELLOW.getName());
        yellowStartPickMaterialVO.setLightSort(2);
        startPickMaterialList.add(yellowStartPickMaterialVO);
        return startPickMaterialList;
    }

    /**
     * 创建RFID电量不足任务
     *
     * @param saveReqVO
     * @return
     */
    private Long createRfidLowBatteryTask(PickTaskSaveReqVO saveReqVO) {
        PickTaskDO pickTaskDO = BeanUtils.toBean(saveReqVO, PickTaskDO.class);
        pickTaskDO.setCode(orderNoRedisDAO.generate(OrderNoRedisDAO.PICK_TASK_NO_PREFIX, RedisKeyConstants.PICK_TASK_NO));
        pickTaskMapper.insert(pickTaskDO);
        return pickTaskDO.getId();
    }

    /**
     * 获取待拣货任务数量
     *
     * @param warehouseId
     * @param statusList
     * @return
     */
    private Long getPickTaskCount(Long warehouseId, List<String> statusList) {
        LambdaQueryWrapperX<PickTaskDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eq(PickTaskDO::getWarehouseId, warehouseId)
                .eq(PickTaskDO::getTaskType, PickTaskTypeEnum.PICK.getType())
                .in(PickTaskDO::getStatus, statusList);
        return pickTaskMapper.selectCount(queryWrapper);
    }
}
